package com.yangyang.rpc.core.netcom;

import com.yangyang.rpc.core.netcom.common.NetComEnum;
import com.yangyang.rpc.core.netcom.common.bean.RpcRequest;
import com.yangyang.rpc.core.netcom.common.bean.RpcResponse;
import com.yangyang.rpc.core.netcom.common.client.AbstractClient;
import com.yangyang.rpc.core.serialize.SerializeEnum;
import com.yangyang.rpc.core.serialize.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;

/**
 * 客户端
 * Created by chenshunyang on 2016/11/20.
 */
public class NetComClientProxyFactoryBean implements FactoryBean<Object>,InitializingBean{
    private Logger logger = LoggerFactory.getLogger(NetComClientProxyFactoryBean.class);
    private String serverAddress;
    private NetComEnum netcom = NetComEnum.NETTY;//默认通信方式为NETTY
    private Serializer serializer  = SerializeEnum.HESSIAN.serializer;//默认序列化方式为HESSION
    private Class<?> iface;
    private long timeoutMillis = 5000;//默认超时时间为5s

    private Object proxyObj;

    private AbstractClient client = null;

    public void setServerAddress(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setNetcom(String netcom) {
        this.netcom = NetComEnum.autoMatch(netcom, NetComEnum.NETTY);
    }

    public void setSerializer(String serializer) {
        this.serializer = SerializeEnum.match(serializer, SerializeEnum.HESSIAN).serializer;
    }

    public void setIface(Class<?> iface) {
        this.iface = iface;
    }

    public void setTimeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化 RPC 客户端
        proxyObj = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{iface}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // request
                        RpcRequest request = new RpcRequest();
                        request.setRequestId(UUID.randomUUID().toString());
                        request.setCreateMillisTime(System.currentTimeMillis());
                        request.setClassName(method.getDeclaringClass().getName());
                        request.setMethodName(method.getName());
                        request.setParameterTypes(method.getParameterTypes());
                        request.setParameters(args);

                        // send
                        RpcResponse response = client.send(request);

                        // valid response
                        if (response == null) {
                            logger.error(">>>>>>>>>>> yy-rpc netty response not found.");
                            throw new Exception(">>>>>>>>>>> yy-rpc netty response not found.");
                        }
                        if (response.isError()) {
                            throw response.getError();
                        } else {
                            return response.getResult();
                        }

                    }
                });
        client = netcom.clientClass.newInstance();
        client.init(serverAddress, serializer, timeoutMillis);
    }

    @Override
    public Object getObject() throws Exception {
        return proxyObj;
    }

    @Override
    public Class<?> getObjectType() {
        return iface;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
